import cnBorder from '../assets/geoData/cnBorder.json';
import { isInChina } from '../utils/mapUtils/isInChina';
import 'ol/ol.css';
import ImageLayer from 'ol/layer/Image';
import { ImageStatic } from 'ol/source';
import * as olProj from 'ol/proj';
import Map from 'ol/Map';
import View from 'ol/View';

import Projection from 'ol/proj/Projection';
import * as olInteraction from 'ol/interaction';
import GeoJSON from 'ol/format/GeoJSON';
import { Tile as TileLayer, Vector as VectorLayer } from 'ol/layer';
import { XYZ, Vector, Cluster } from 'ol/source';
import Feature from 'ol/Feature';
import {
    Point,
    LineString,
    MultiLineString,
    Polygon,
    MultiPolygon
} from 'ol/geom';

import Overlay from 'ol/Overlay';
import {
    Circle,
    RegularShape,
    Fill,
    Text,
    Stroke,
    Style,
    Icon
} from 'ol/style';
import * as olExtent from 'ol/extent';
import {
    Draw,
    Modify,
    Select,
    Snap,
    DragPan,
    DoubleClickZoom,
    MouseWheelZoom
} from 'ol/interaction';

import { platformModifierKeyOnly } from 'ol/events/condition';

import { roundRectBackground } from '../utils/mapUtils/labelIcon.js';

import { createTileLayer } from '../utils/mapUtils/layer.js';

import { isoBnad, filterIsoband } from '../utils/mapUtils/isoband.js';

class CuiteMap {
    constructor(map) {
        this.map = map;
        this.overlay = null;
        // this.popupOverlay = null;
        this.vectorLayer = null;
        this.imageLayer = null;
        this.cvaLayer = null;
        this.tileLayers = {};
        this.vectorLayers = {};
        this.callbackCollection = {};
        // this.addPopupOverLayer();
        this.bindClickEvent();
        // this.map.on('click', e => {
        //   console.log(e);
        // })
    }
    bindClickEvent() {
        this.map.on('click', e => {
            var feature = this.map.forEachFeatureAtPixel(e.pixel, feature => {
                return feature;
            });
            this.clearMap();
            if (feature) {
                let data = feature.getProperties();
                if (data['features']) {
                    if (data['features'].length == 1) {
                        data = data['features'][0].getProperties();
                        if (this.callbackCollection[data['layertype']]) {
                            this.callbackCollection[data['layertype']](data);
                            this.setOverlayerCoordinate(e.coordinate);
                        }
                    }
                } else {
                    if (this.callbackCollection[data['layertype']]) {
                        this.callbackCollection[data['layertype']](data);
                        this.setOverlayerCoordinate(e.coordinate);
                    }
                }
            } else {
                this.getLayer('search')
                    .getSource()
                    .clear();
            }
        });
    }
    exportMap(callback) {
        var mapCanvas = document.createElement('canvas');
        var size = this.map.getSize();
        mapCanvas.width = size[0];
        mapCanvas.height = size[1];
        var mapContext = mapCanvas.getContext('2d');
        Array.prototype.forEach.call(
            document.querySelectorAll('.ol-layer canvas'),
            function (canvas) {
                if (canvas.width > 0) {
                    var opacity = canvas.parentNode.style.opacity;
                    mapContext.globalAlpha = opacity === '' ? 1 : Number(opacity);
                    var transform = canvas.style.transform;
                    var matrix = transform
                        .match(/^matrix\(([^\(]*)\)$/)[1]
                        .split(',')
                        .map(Number);
                    CanvasRenderingContext2D.prototype.setTransform.apply(
                        mapContext,
                        matrix
                    );
                    mapContext.drawImage(canvas, 0, 0);
                }
            }
        );
        if (navigator.msSaveBlob) {
            navigator.msSaveBlob(mapCanvas.msToBlob(), 'map.png');
        } else {
            // var link = document.getElementById('image-download');
            // link.href = mapCanvas.toDataURL();
            // link.click();
            if (callback) {
                const base64 = mapCanvas.toDataURL('image/png');
                callback(base64);
            }
        }
    }
    setOverlayerCoordinate(coordinates) {
        this.overlay.setPosition(coordinates);
        let offset = this.getPopupOffset(coordinates);
        this.overlay.setOffset(offset);
    }
    getPiexlCoordinates(offset) {
        var pixel = [
            window.innerWidth / 2 + offset[0],
            window.innerHeight / 2 + offset[1]
        ];
        var point = this.map.getCoordinateFromPixel(pixel);
        return point;
    }
    getPopupOffset(coordinates) {
        let xy = this.map.getPixelFromCoordinate(coordinates);
        let screenSize = [
            document.getElementById('map').clientWidth,
            document.getElementById('map').clientHeight
        ];
        let popupSize = [
            document.getElementById('popup').clientWidth,
            document.getElementById('popup').clientHeight
        ];
        let leftOffset = 0;
        if (document.getElementById('contentbox')) {
            let display = document.getElementById('contentbox').style.display;
            if (display == '' || display == 'block') {
                leftOffset = document.getElementById('contentbox').clientWidth;
            }
        }
        let offset = [0, 0];
        if (xy[1] < popupSize[1]) {
            //顶部
            offset[1] = popupSize[1] + 24;
        }
        if (xy[0] - leftOffset < popupSize[0] - 48) {
            //左侧区域
            offset[0] = 48 + 12;
        }
        if (xy[0] + popupSize[0] > screenSize[0]) {
            //右侧区域
            offset[0] = -(popupSize[0] - 48) - 12;
        }
        return offset;
    }
    clearMap() {
        this.overlay.setPosition(undefined);
        this.getLayer('search')
            .getSource()
            .clear();
    }
    addPopupOverLayer() {
        this.popupOverlay = new Overlay({
            element: document.getElementById('popup1'),
            autoPan: false,
            autoPanAnimation: {
                duration: 250
            }
        });
        this.map.addOverlay(this.popupOverlay);
        let closer = document.getElementById('popup-closer1');
        closer.addEventListener('click', () => {
            this.popupOverlay.setPosition(undefined);
            closer.blur();
            return false;
        });
    }
    addOverLayer() {
        this.overlay = new Overlay({
            element: document.getElementById('popup'),
            autoPan: false,
            autoPanAnimation: {
                duration: 250
            }
        });
        this.map.addOverlay(this.overlay);
        const closer = document.getElementById('popup-closer');
        closer.addEventListener('click', () => {
            this.overlay.setPosition(undefined);
            closer.blur();
            return false;
        });
    }
    initBaseLayer(config) {
        config.forEach(item => {
            if (item['title'] == '3857_vec') {
                this.vectorLayer = createTileLayer(item['sourceUrl']);
                this.map.addLayer(this.vectorLayer);
            } else if (item['title'] == '3857_img') {
                this.imageLayer = createTileLayer(item['sourceUrl']);
                this.map.addLayer(this.imageLayer);
                this.imageLayer.setVisible(false);
            } else if (item['title'] == '3857_cva') {
                this.cvaLayer = createTileLayer(item['sourceUrl']);
                this.map.addLayer(this.cvaLayer);
            }
        });
    }
    changeBaseLayer(active) {
        if (active) {
            this.vectorLayer.setVisible(false);
            this.imageLayer.setVisible(true);
        } else {
            this.vectorLayer.setVisible(true);
            this.imageLayer.setVisible(false);
        }
    }
    initImageLayer(id, url, extent) {
        if (!this.tileLayers[id]) {
            this.tileLayers[id] = new ImageLayer({
                source: new ImageStatic({
                    url: url,
                    imageExtent: extent
                }),
                opacity: 0.8
            });
            this.map.addLayer(this.tileLayers[id]);
        }
    }
    initLayer(id, style, callback) {
        if (!this.vectorLayers[id]) {
            (this.vectorLayers[id] = new VectorLayer({
                source: new Vector({
                    features: [],
                    wrapX: false
                }),
                style: feature => {
                    if (style) {
                        feature.setStyle(this.createStyle(style, feature));
                    }
                },
                opacity: 1,
                selectedStyle: style
            })),
                this.map.addLayer(this.vectorLayers[id]);
            if (callback) {
                this.callbackCollection[id] = callback;
                // this.bindClickEvent(id, callback)
            }
        }
    }
    initClusterLayer(id, style, callback) {
        if (!this.vectorLayers[id]) {
            let source = new Vector({
                features: [],
                wrapX: false
            });
            source = new Cluster({
                distance: 40,
                source: new Vector(),
                wrapX: false
            });
            (this.vectorLayers[id] = new VectorLayer({
                source: source,
                style: feature => {
                    let features = feature.getProperties().features;
                    if (style) {
                        if (features.length == 1) {
                            feature.setStyle(this.createStyle(style));
                        } else {
                            feature.setStyle(
                                new Style({
                                    image: new Circle({
                                        stroke: new Stroke({
                                            color: 'rgba(50,133,255,1)',
                                            width: 1
                                        }),
                                        fill: new Fill({
                                            color: 'rgba(50,133,255,0.5)'
                                        }),
                                        radius: Math.sqrt(features.length) + 12
                                    }),
                                    text: new Text({
                                        textAlign: 'center',
                                        textBaseline: 'middle',
                                        font: 'normal 12px 黑体',
                                        text: features.length.toString(),
                                        offsetX: 0,
                                        offsetY: 0,
                                        overflow: true,
                                        fill: new Fill({
                                            color: '#FFF'
                                        })
                                    })
                                })
                            );
                        }
                    } else {
                        if (features.length === 1) {
                            const item = features[0].getProperties();
                            const sName = item.staionName;
                            feature.setStyle(
                                new Style({
                                    image: new Icon({
                                        scale: 1,
                                        anchor: [0.5, -0.3],
                                        anchorXUnits: 'fraction',
                                        anchorYUnits: 'fraction',
                                        src: roundRectBackground(
                                            `${sName.replace('气象观测站', '')}：${item.timeValue}mm`,
                                            [4, 24, 4, 24]
                                        )
                                    })
                                })
                            );
                        } else {
                            feature.setStyle(
                                new Style({
                                    image: new Circle({
                                        stroke: new Stroke({
                                            color: 'rgba(0,0,0,0)',
                                            width: 0
                                        }),
                                        fill: new Fill({
                                            color: 'rgba(0,0,0,0)'
                                        }),
                                        radius: 0.001
                                    })
                                })
                            );
                        }
                    }
                },
                opacity: 1
            })),
                this.map.addLayer(this.vectorLayers[id]);
            if (callback) {
                this.callbackCollection[id] = callback;
            }
        }
    }
    fitToPoint(lon, lat) {
        const point = olProj.transform([lon, lat], 'EPSG:4326', 'EPSG:3857');
        this.map.getView().animate(
            {
                center: point
            },
            {
                zoom: 16
            }
        );
    }
    getLayer(id) {
        this.initLayer(id);
        return this.vectorLayers[id];
    }
    getImageLayer(id) {
        return this.tileLayers[id];
    }
    addIsoBandLayer(id, data) {
        this.getLayer(id)
            .getSource()
            .clear();
        if (data && data.length) {
            let features = isoBnad(data);
            this.getLayer(id)
                .getSource()
                .addFeatures(features);
            let crop = filterIsoband();
            this.getLayer(id).addFilter(crop);
        }
    }
    addFeatureLayer(id, data, nolabel) {
        this.getLayer(id)
            .getSource()
            .clear();
        let features = [];
        data.forEach(item => {
            if (!item['lon'] || !item['lat']) return;
            let point = olProj.transform(
                [parseFloat(item['lon']), parseFloat(item['lat'])],
                'EPSG:4326',
                'EPSG:3857'
            );
            let feature = new Feature(new Point(point));
            item['layertype'] = id;
            feature.setProperties(item);
            features.push(feature);
            if (!nolabel) {
                let labelfeature = new Feature(new Point(point));
                // TODO: 切换时效要重新渲染站点
                const sName = item.staionName;
                labelfeature.setStyle(
                    new Style({
                        image: new Icon({
                            scale: 1,
                            anchor: [0.5, -0.3],
                            anchorXUnits: "fraction",
                            anchorYUnits: "fraction",
                            src: roundRectBackground(
                                `${sName.replace("气象观测站", "") + ": " + item.timeValue}mm`,
                                [4, 24, 4, 24]
                            ) // ${item.staionName} timeValue:风险值
                        })
                    })
                );
                features.push(labelfeature);
            }
        });
        this.getLayer(id)
            .getSource()
            .addFeatures(features);
    }
    addClusterFeatureLayer(id, data) {
        this.getLayer(id)
            .getSource()
            .clear();
        let features = [];
        data.forEach(item => {
            if (!item["lon"] || !item["lat"]) return;
            let point = olProj.transform(
                [parseFloat(item["lon"]), parseFloat(item["lat"])],
                "EPSG:4326",
                "EPSG:3857"
            );
            let feature = new Feature(new Point(point));
            item["layertype"] = id;
            feature.setProperties(item);
            features.push(feature);
        });
        this.getLayer(id)
            .getSource()
            .setSource(
                new Vector({
                    features: features
                })
            );
    }
    addGeoJSONLayer(id, geojsonObject) {
        this.getLayer(id)
            .getSource()
            .clear();
        let features = new GeoJSON().readFeatures(geojsonObject, {
            dataProjection: "EPSG:4326",
            featureProjection: "EPSG:3857"
        });
        this.getLayer(id)
            .getSource()
            .addFeatures(features);
    }
    createStyle(config, feature) {
        let style = null;
        if (config["image_url"]) {
            //图片
            style = new Style({
                image: new Icon({
                    scale: config["image_scale"] || 1,
                    anchor: [
                        config["image_anchor_x"] || 0.5,
                        config["image_anchor_y"] || 0.5
                    ],
                    anchorXUnits: "fraction",
                    anchorYUnits: "fraction",
                    src: config["image_url"]
                })
            });
        } else {
            if (config["icon_type"]) {
                if (config["icon_type"] == "square") {
                    style = new Style({
                        image: new RegularShape({
                            stroke: new Stroke({
                                color: config["stroke_color"],
                                width: config["stroke_width"]
                            }),
                            fill: new Fill({
                                color: config["fill_color"]
                            }),
                            points: 4,
                            radius: config["icon_size"],
                            angle: Math.PI / 4,
                            rotation: (config["icon_roate"] * Math.PI) / 180
                        }),
                        stroke: new Stroke({
                            color: config["stroke_color"],
                            width: config["stroke_width"]
                        }),
                        fill: new Fill({
                            color: config["fill_color"]
                        })
                    });
                } else if (config["icon_type"] == "circle") {
                    style = new Style({
                        image: new Circle({
                            stroke: new Stroke({
                                color: config["stroke_color"],
                                width: config["stroke_width"]
                            }),
                            fill: new Fill({
                                color: config["fill_color"]
                            }),
                            radius: config["icon_size"]
                        }),
                        stroke: new Stroke({
                            color: config["stroke_color"],
                            width: config["stroke_width"]
                        }),
                        fill: new Fill({
                            color: config["fill_color"]
                        })
                    });
                } else if (config["icon_type"] == "triangle") {
                    style = new Style({
                        image: new RegularShape({
                            stroke: new Stroke({
                                color: config["stroke_color"],
                                width: config["stroke_width"]
                            }),
                            fill: new Fill({
                                color: config["fill_color"]
                            }),
                            points: 3,
                            radius: config["icon_size"],
                            angle: 0,
                            rotation: (config["icon_roate"] * Math.PI) / 180
                        }),
                        stroke: new Stroke({
                            color: config["stroke_color"],
                            width: config["stroke_width"]
                        }),
                        fill: new Fill({
                            color: config["fill_color"]
                        })
                    });
                } else if (config["icon_type"] == "star") {
                    style = new Style({
                        image: new RegularShape({
                            stroke: new Stroke({
                                color: config["stroke_color"],
                                width: config["stroke_width"]
                            }),
                            fill: new Fill({
                                color: config["fill_color"]
                            }),
                            points: 5,
                            radius: config["icon_size"],
                            radius2: config["icon_size"] * 0.4,
                            angle: 0,
                            rotation: (config["icon_roate"] * Math.PI) / 180
                        }),
                        stroke: new Stroke({
                            color: config["stroke_color"],
                            width: config["stroke_width"]
                        }),
                        fill: new Fill({
                            color: config["fill_color"]
                        })
                    });
                } else if (config["icon_type"] == "cross") {
                    style = new Style({
                        image: new RegularShape({
                            stroke: new Stroke({
                                color: config["stroke_color"],
                                width: config["stroke_width"]
                            }),
                            fill: new Fill({
                                color: config["fill_color"]
                            }),
                            points: 4,
                            radius: config["icon_size"],
                            radius2: 0,
                            angle: 0,
                            rotation: (config["icon_roate"] * Math.PI) / 180
                        }),
                        stroke: new Stroke({
                            color: config["stroke_color"],
                            width: config["stroke_width"]
                        }),
                        fill: new Fill({
                            color: config["fill_color"]
                        })
                    });
                } else if (config["icon_type"] == "x") {
                    style = new Style({
                        image: new RegularShape({
                            stroke: new Stroke({
                                color: config["stroke_color"],
                                width: config["stroke_width"]
                            }),
                            fill: new Fill({
                                color: config["fill_color"]
                            }),
                            points: 4,
                            radius: config["icon_size"],
                            radius2: 0,
                            angle: Math.PI / 4,
                            rotation: (config["icon_roate"] * Math.PI) / 180
                        }),
                        stroke: new Stroke({
                            color: config["stroke_color"],
                            width: config["stroke_width"]
                        }),
                        fill: new Fill({
                            color: config["fill_color"]
                        })
                    });
                }
            } else {
                if (config["fill_color"]) {
                    style = new Style({
                        stroke: new Stroke({
                            color: config["stroke_color"],
                            width: config["stroke_width"]
                        }),
                        fill: new Fill({
                            color: config["fill_color"]
                        })
                    });
                } else {
                    style = new Style({
                        stroke: new Stroke({
                            lineDash: config["stroke_dashe"]
                                ? [
                                    config["stroke_width"],
                                    config["stroke_width"] + config["stroke_dashe"]
                                ]
                                : [config["stroke_width"], 0],
                            color: config["stroke_color"],
                            width: config["stroke_width"]
                        })
                    });
                }
            }
        }

        if (config["text_filed"]) {
            let font_color = config["font_color"] || "rgba(0,0,255,0.8)";
            let font = config["font"] || "黑体";
            let font_size = config["font_size"] || 12;
            let text_align = config["text_align"] || "center";
            let font_offsetx = config["font_offsetx"] || 0;
            let font_offsety = config["font_offsety"] || -20;
            let text = feature ? feature.get(config["text_filed"]) : "";
            let textStyle = new Text({
                textAlign: text_align,
                textBaseline: "middle",
                font: "normal " + font_size + "px " + font,
                text: text.toString(),
                offsetX: font_offsetx,
                offsetY: font_offsety,
                overflow: true,
                fill: new Fill({
                    color: font_color
                })
            });
            style.setText(textStyle);
        }
        return style;
    }
}

export default CuiteMap;
